home *** CD-ROM | disk | FTP | other *** search
- Path: xanth!mcnc!rutgers!tut.cis.ohio-state.edu!cwjcc!hal!ncoast!allbery
- From: george@rebel.UUCP (George M. Sipe)
- Newsgroups: comp.sources.misc
- Subject: v04i122: extended access control for Unix
- Message-ID: <48341@rebel.UUCP>
- Date: 11 Oct 88 02:25:39 GMT
- Sender: allbery@ncoast.UUCP
- Reply-To: george@rebel.UUCP (George M. Sipe)
- Organization: Tolerant Systems, Atlanta GA
- Lines: 1046
- Approved: allbery@ncoast.UUCP
-
- Posting-number: Volume 4, Issue 122
- Submitted-by: "George M. Sipe" <george@rebel.UUCP>
- Archive-name: access
-
- [I stand corrected... (Sorry, Rich, you slowpoke! ;-) ++bsa]
-
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create:
- # README
- # Makefile
- # access.c
- # access.man
- # This archive created: Tue Jul 19 13:02:15 1988
- export PATH; PATH=/bin:/usr/bin:$PATH
- if test -f 'README'
- then
- echo shar: "will not over-write existing file 'README'"
- else
- sed 's/^X//' << \SHAR_EOF > 'README'
- XAccess provides a simple yet powerful method of controlling user access
- Xto a system. Simply specify access in place of a login shell in the
- Xpassword file for each user who is to have restricted accessibility to
- Xa system. Access will in turn, execute the login shell specified in
- Xits argument list if the current tty and time falls within one or more
- Xof the access constraints given.
- X
- XAccessibility constraints limit users by tty port and/or up to 6
- Xaccessibility classes of time.
- X
- XOne of the most valued uses of access is to reserve modem use for UUCP
- Xor high priority users. See the manual page for examples.
- X
- XBe sure to disable users ability to change their login shell and
- Xthereby defeat this control. For example, "chmod o-x /usr/ucb/chsh".
- X
- X
- X Copyright (c) 1988 by George M. Sipe. All rights reserved.
- X
- XThis software may only be redistributed without fee and without any
- Xother form of monetary gain (including sold, rented, leased, or
- Xtraded), unless the express written permission of the copyright holder
- Xis obtained in advance.
- X
- XThis copyright notice must be reproduced in its entirety on all copies
- Xof this software. Further, acknowledgment of the authorship of this
- Xsoftware must not be removed from its current or derived
- Xdocumentation.
- X
- XNo expressed or implied warranty is made for this software. No party
- Xconnected with this software assumes any liability or responsibility
- Xfor its use, the correctness of its operation, or its fitness for any
- Xpurpose.
- X
- XAny distributor of copies of this software shall grant the recipient
- Xpermission for further redistribution as permitted by this notice.
- X
- XPermission is hereby granted to copy, reproduce, redistribute and
- Xotherwise use this software as long as the conditions above are
- Xstrictly adhered to.
- SHAR_EOF
- fi
- if test -f 'Makefile'
- then
- echo shar: "will not over-write existing file 'Makefile'"
- else
- sed 's/^X//' << \SHAR_EOF > 'Makefile'
- X# Makefile for: access - limit system usage to specified ttys and times
- X
- XDEFINES = -DBSD
- XCFLAGS = -O $(DEFINES)
- XROFF = nroff
- XRFLAGS = -man
- XLDFLAGS = -s
- XDESTBIN = ${HOME}
- XDESTMAN = ${HOME}
- XDESTCAT = ${HOME}
- XDESTOWN = root
- XDESTGRP = staff
- XSHELL = /bin/sh
- XMAKEFILE = Makefile
- XPROGRAM = access
- XMANPAGES = access.man
- XCATPAGES = access.cat
- XSRCS = access.c
- XOBJS = access.o
- X
- X.man.cat:
- X $(ROFF) $(RFLAGS) $< > $@
- X
- X.SUFFIXES: .man .cat
- X
- X# Compile and load the program and format its manual pages.
- Xall: $(PROGRAM) $(CATPAGES)
- X
- X$(PROGRAM): $(OBJS)
- X $(CC) $(LDFLAGS) $(OBJS) -o $(PROGRAM)
- X
- X# Run lint on source files, put results on standard output.
- Xlint:
- X lint -u $(DEFINES) $(SRCS)
- X
- X# Create a tags file for use by a source code editor.
- Xtags: $(SRCS)
- X ctags $(SRCS)
- X
- X# Edit the makefile and regenerate the dependency information.
- Xdepend:
- X mkmf -f $(MAKEFILE) PROGRAM=$(PROGRAM) DESTBIN=$(DESTBIN)
- X
- X# Print an index of functions on standard output.
- Xindex:
- X ctags -wx $(SRCS)
- X
- X# Print source code files on standard output.
- Xprint:
- X lpr -p $(SRCS) $(MANPAGES)
- X
- X# Compile and load the program, format manual pages, and move them
- X# to their destination directories.
- Xinstall: $(PROGRAM) $(CATPAGES)
- X cp $(PROGRAM) $(DESTBIN)
- X chmod 755 $(DESTBIN)/$(PROGRAM)
- X chown $(DESTOWN) $(DESTBIN)/$(PROGRAM)
- X chgrp $(DESTGRP) $(DESTBIN)/$(PROGRAM)
- X -for manpage in $(MANPAGES); do \
- X basepage=`basename $$manpage .man`; \
- X cp $$basepage.man $(DESTMAN)/$$basepage.l; \
- X chmod 644 $(DESTMAN)/$$basepage.l; \
- X chown $(DESTOWN) $(DESTMAN)/$$basepage.l; \
- X chgrp $(DESTGRP) $(DESTMAN)/$$basepage.l; \
- X cp $$basepage.cat $(DESTCAT)/$$basepage.l; \
- X chmod 644 $(DESTCAT)/$$basepage.l; \
- X chown $(DESTOWN) $(DESTCAT)/$$basepage.l; \
- X chgrp $(DESTGRP) $(DESTCAT)/$$basepage.l; \
- X done
- X
- X# Remove the program and its formatted manual pages from their
- X# destination directories.
- Xuninstall:
- X rm -f $(DESTBIN)/$(PROGRAM)
- X -for manpage in $(MANPAGES); do \
- X basepage=`basename $$manpage .man`; \
- X rm -f $(DESTMAN)/$$basepage.l; \
- X rm -f $(DESTCAT)/$$basepage.l; \
- X done
- X
- X# Remove all target and intermediate files.
- Xclean:
- X -rm -f $(PROGRAM) $(CATPAGES) $(OBJS)
- X -rm -f core a.out made *.o
- SHAR_EOF
- fi
- if test -f 'access.c'
- then
- echo shar: "will not over-write existing file 'access.c'"
- else
- sed 's/^X//' << \SHAR_EOF > 'access.c'
- X/* Copyright (c) 1988 by George M. Sipe. All rights reserved.
- X
- XThis software may only be redistributed without fee and without any
- Xother form of monetary gain (including sold, rented, leased, or
- Xtraded), unless the express written permission of the copyright holder
- Xis obtained in advance.
- X
- XThis copyright notice must be reproduced in its entirety on all copies
- Xof this software. Further, acknowledgment of the authorship of this
- Xsoftware must not be removed from its current or derived
- Xdocumentation.
- X
- XNo expressed or implied warranty is made for this software. No party
- Xconnected with this software assumes any liability or responsibility
- Xfor its use, the correctness of its operation, or its fitness for any
- Xpurpose.
- X
- XAny distributor of copies of this software shall grant the recipient
- Xpermission for further redistribution as permitted by this notice.
- X
- XPermission is hereby granted to copy, reproduce, redistribute and
- Xotherwise use this software as long as the conditions above are
- Xstrictly adhered to. */
- X
- X#include <stdio.h>
- X#include <ctype.h>
- X#include <pwd.h>
- X#include <sys/types.h>
- X#ifndef BSD
- X#include <time.h>
- X#define MAXPATHLEN 1024
- Xvoid exit();
- Xchar *strchr();
- Xchar *strrchr();
- Xlong time();
- X#else
- X#include <sys/time.h>
- X#include <sys/param.h>
- X#undef MIN
- X#define strchr(s,c) index(s,c)
- X#define strrchr(s,c) rindex(s,c)
- Xexit();
- Xchar *index();
- Xchar *rindex();
- Xtime_t time();
- X#endif
- X
- Xint execve();
- Xint fclose();
- Xint fgetc();
- Xchar *fgets();
- XFILE *fopen();
- Xint fputc();
- Xint fputs();
- Xint geteuid();
- Xstruct passwd *getpwuid();
- Xstruct tm *localtime();
- Xchar *strcat();
- Xchar *strcpy();
- Xint strlen();
- Xint strncmp();
- Xchar *ttyname();
- Xint ungetc();
- X
- X/* #define DEBUG /* define for tracing information */
- X
- X#ifndef TRUE
- X#define TRUE 1 /* true and false */
- X#define FALSE 0
- X#endif
- X#define UNSET 3 /* unset flag */
- X
- X#ifndef DEBUG
- X#define ACFILE "/usr/local/lib/access"
- X#else
- X#define ACFILE "test"
- X#endif DEBUG
- X#define MAXENT 1024 /* maximum entry length */
- X#define MAXARGS 99 /* maximum number of arguments in file */
- X#define MAXSH MAXPATHLEN+7 /* maximum size of SHELL environment variable */
- X
- X#define TTY 't' /* ttyname restrictor */
- X#define MIN 'm' /* minute restrictor */
- X#define HOUR 'h' /* hour restrictor */
- X#define WDAY 'w' /* day of week restrictor */
- X#define MDAY 'D' /* day of month restrictor */
- X#define MON 'M' /* month restrictor */
- X#define YEAR 'Y' /* year restrictor */
- X#define OR 'o' /* logical or separator */
- X#define PATH '/' /* pathname prefix */
- X
- X#define ERRNTTY 101 /* not connected to a tty */
- X#define ERRSEP 102 /* missing separator between values */
- X#define ERRRNG1 103 /* '-' appears twice in range */
- X#define ERRRNG2 104 /* '-' does not follow value */
- X#define ERRNUL 105 /* null value */
- X#define ERRMIN 106 /* value below minimum */
- X#define ERRMAX 107 /* value exceeds maximum */
- X#define ERRBAD 108 /* invalid character */
- X
- Xtypedef char BOOL;
- X
- Xstatic struct tm *timenow; /* the current local time */
- Xstatic char *name = NULL; /* pointer to username */
- Xstatic int namesz; /* size of username */
- Xstatic char *ttynm = NULL; /* pointer to ttyname */
- Xstatic int ttysz; /* size of ttyname */
- X
- Xstatic BOOL user; /* TRUE or FALSE */
- Xstatic BOOL tty; /* UNSET, TRUE, or FALSE */
- Xstatic BOOL min[60]; /* 0 to 59 */
- Xstatic BOOL hour[24]; /* 0 to 23 */
- Xstatic BOOL wday[8]; /* 0 (Sunday) to 6 (Saturday); 7 = 0 too */
- Xstatic BOOL mday[32]; /* 1 to 31 */
- Xstatic BOOL mon[13]; /* 1 to 12 */
- Xstatic BOOL year[99]; /* 87 to 99 */
- X
- X/* Display userchk(), ttychk(), and expand() error message. */
- X
- Xstatic void error(type, string, code)
- Xchar *type;
- Xchar *string;
- Xint code;
- X{
- X fputs("\n*** system access processing failure - ", stderr);
- X fputs("report to your system manager ***\n\n", stderr);
- X
- X if (code == 0) {
- X fputs(type, stderr);
- X fputs(string, stderr);
- X fputc('\n', stderr);
- X exit(0);
- X }
- X
- X fputs("invalid ", stderr);
- X fputs(type, stderr);
- X fputs(" specification: '", stderr);
- X fputs(string, stderr);
- X fputs("' ", stderr);
- X switch (code) {
- X case ERRNTTY:
- X fputs("(not connected to a tty)\n", stderr);
- X break;
- X case ERRSEP:
- X fputs("(missing separator between values)\n", stderr);
- X break;
- X case ERRRNG1:
- X fputs("('-' appears twice in range)\n", stderr);
- X break;
- X case ERRRNG2:
- X fputs("('-' does not follow value)\n", stderr);
- X break;
- X case ERRNUL:
- X fputs("(null value)\n", stderr);
- X break;
- X case ERRMIN:
- X fputs("(value below minimum)\n", stderr);
- X break;
- X case ERRMAX:
- X fputs("(value exceeds maximum)\n", stderr);
- X break;
- X case ERRBAD:
- X fputs("(invalid character)\n", stderr);
- X break;
- X default:
- X fputs("(indeterminant error)\n", stderr);
- X break;
- X }
- X exit(0);
- X}
- X
- X/* Given a string containing usernames, check them against the current
- X user's name. If there is a match, set the global 'user' to TRUE
- X otherwise set 'user' to FALSE. In addition to a direct match, 'user'
- X may be set to TRUE by '*'. Further, '!' may be used to negate its
- X meaning. Return FALSE if no errors, error number otherwise.
- X*/
- X
- Xstatic int userchk(string)
- Xchar *string;
- X{
- X register char *cp, *s1;
- X register BOOL seen = FALSE;
- X register BOOL negate = FALSE;
- X struct passwd *passwd;
- X
- X if (!name) {
- X if (!(passwd = getpwuid(geteuid())))
- X error("could not access passwd entry", "", 0);
- X name = passwd->pw_name;
- X namesz = strlen(name);
- X#ifdef DEBUG
- X fputs("My username is: ", stderr);
- X fputs(name, stderr);
- X fputs("\n", stderr);
- X#endif DEBUG
- X }
- X user = FALSE;
- X for (cp = string; ; ) switch (*cp) {
- X case ' ': /* whitespace terminates immediately */
- X case '\t':
- X case '#':
- X case '\n':
- X return (FALSE);
- X case '!': /* negation requested */
- X case '^':
- X /* be sure nothing yet specified */
- X if (seen) return (ERRSEP);
- X negate = !negate;
- X ++cp;
- X break;
- X case '*': /* every username */
- X case '@':
- X /* be sure nothing yet specified */
- X if (seen) return (ERRSEP);
- X seen = TRUE;
- X user = !negate;
- X ++cp;
- X break;
- X case '\000': /* string/specification end */
- X case ',': /* specification end */
- X /* be sure value was found */
- X if (!seen) return (ERRNUL);
- X if (!*cp) return (FALSE);
- X seen = FALSE;
- X negate = FALSE;
- X ++cp;
- X break;
- X default: /* user specification found */
- X /* be sure nothing yet specified */
- X if (seen) return (ERRSEP);
- X seen = TRUE;
- X s1 = cp;
- X /* find the end of the specification */
- X while (*cp && !strchr(" \t#\n!^*@,", *cp)) ++cp;
- X /* see if it doesn't match by definition */
- X if ((cp - s1) != namesz) break;
- X /* see if it doesn't match */
- X if (strncmp(name, s1, namesz)) break;
- X user = !negate;
- X break;
- X }
- X}
- X
- X/* Given a string containing the trailing portion of a ttyname, check
- X it against the current tty's name. If it matches, set the global
- X 'tty' to TRUE. The first time ttychk() is called within an overall
- X specification, 'tty' is set to FALSE. It may be set to TRUE by '*'
- X at any time. Further, '!' may be used to negate its meaning. Return
- X FALSE if no errors, error number otherwise.
- X*/
- X
- Xstatic int ttychk(string)
- Xchar *string;
- X{
- X register char *cp, *s1, *s2;
- X register BOOL seen = FALSE;
- X register BOOL negate = FALSE;
- X
- X if (!ttynm) {
- X if (!(ttynm = ttyname(0))) return (ERRNTTY);
- X ttysz = strlen(ttynm);
- X#ifdef DEBUG
- X fputs("My ttyname is: ", stderr);
- X fputs(ttynm, stderr);
- X fputs("\n", stderr);
- X#endif DEBUG
- X }
- X if (tty == UNSET) tty = FALSE;
- X cp = string + 1; /* skip first byte */
- X for (;;) switch (*cp) {
- X case ' ': /* skip whitespace */
- X case '\t':
- X ++cp;
- X break;
- X case '!': /* negation requested */
- X case '^':
- X /* be sure nothing yet specified */
- X if (seen) return (ERRSEP);
- X negate = !negate;
- X ++cp;
- X break;
- X case '*': /* every ttyname */
- X case '@':
- X /* be sure nothing yet specified */
- X if (seen) return (ERRSEP);
- X seen = TRUE;
- X tty = !negate;
- X ++cp;
- X break;
- X case '\000': /* string/specification end */
- X case ',': /* specification end */
- X /* be sure value was found */
- X if (!seen) return (ERRNUL);
- X if (!*cp) return (FALSE);
- X seen = FALSE;
- X negate = FALSE;
- X ++cp;
- X break;
- X case '-': /* '-' does not follow value */
- X return (ERRRNG2);
- X default: /* tty specification found */
- X /* be sure nothing yet specified */
- X if (seen) return (ERRSEP);
- X seen = TRUE;
- X s1 = cp;
- X /* find the end of the specification */
- X while (*cp && !strchr(" \t!^*@,-", *cp)) ++cp;
- X s2 = ttynm + ttysz - (cp - s1);
- X /* see if it doesn't match by definition */
- X if (s2 < ttynm) break;
- X /* check for simple non-range specification */
- X if (*cp != '-') {
- X /* see if it doesn't match */
- X if (strncmp(s2, s1, cp - s1)) break;
- X tty = !negate;
- X break;
- X }
- X /* see if < start of range */
- X if (strncmp(s2, s1, cp - s1) < 0) {
- X /* it is, skip past range limit */
- X ++cp;
- X while (*cp && !strchr(" \t!^*@,-", *cp)) ++cp;
- X if (*cp == '-') return (ERRRNG1);
- X break;
- X }
- X /* find the start and end of range limit */
- X s1 = ++cp;
- X while (*cp && !strchr(" \t!^*@,-", *cp)) ++cp;
- X if (*cp == '-') return (ERRRNG1);
- X s2 = ttynm + ttysz - (cp - s1);
- X /* see if it doesn't match by definition */
- X if (s2 < ttynm) break;
- X /* see if > end of range */
- X if (strncmp(s2, s1, cp - s1) > 0) break;
- X tty = !negate;
- X break;
- X }
- X}
- X
- X/* Extract a positive, integer value from the string pointed to by
- X 'cp' into the int pointed to by 'pnum'. Return the first non-digit
- X position in 'cp'.
- X*/
- X
- Xstatic char *getnum(cp, pnum)
- Xchar *cp;
- Xint *pnum;
- X{
- X register int num = 0;
- X
- X while (isdigit(*cp)) num = num * 10 + (*cp++ - '0');
- X *pnum = num;
- X return (cp);
- X}
- X
- X/* Given a string containing numeric values and ranges separated by
- X commas - generate a truth vector between 0 and 'max'-1 for those
- X values which are specified. Example: "2,4,6-10,14". The first
- X time expand() is called for a given vector, all values are set to
- X FALSE. Thereafter, new values are added to the existing vector.
- X Note: any single number or range may be preceeded by '!' to negate
- X its meaning (set the specified values to FALSE). An example might
- X be "*,!9-17". Further note: the first byte of the specified string
- X is ignored. Return FALSE if no errors, error number otherwise.
- X*/
- X
- Xstatic int expand(string, vector, minimum, maximum)
- Xchar *string;
- XBOOL vector[];
- Xint minimum, maximum;
- X{
- X register char *cp;
- X register int i;
- X register int range = -1;
- X register BOOL negate = FALSE;
- X int num = -1;
- X
- X if (vector[0] == UNSET)
- X for (i = 0; i <= maximum; ++i) vector[i] = FALSE;
- X cp = string + 1; /* skip first byte */
- X for (;;) switch (*cp) {
- X case ' ': /* skip whitespace */
- X case '\t':
- X ++cp;
- X break;
- X case '!': /* negation requested */
- X case '^':
- X /* be sure value is new */
- X if (num >= 0) return (ERRSEP);
- X negate = !negate;
- X ++cp;
- X break;
- X case '*': /* full range */
- X case '@':
- X /* be sure value is new */
- X if (num >= 0) return (ERRSEP);
- X /* check for range started */
- X if (range >= 0) {
- X num = maximum;
- X ++cp;
- X break;
- X }
- X /* no range yet */
- X ++cp;
- X while (*cp == ' ' || *cp == '\t') ++cp;
- X /* check for range continued */
- X if (*cp == '-') {
- X num = minimum;
- X } else {
- X range = minimum;
- X num = maximum;
- X }
- X break;
- X case '0': /* value found */
- X case '1':
- X case '2':
- X case '3':
- X case '4':
- X case '5':
- X case '6':
- X case '7':
- X case '8':
- X case '9':
- X /* be sure value is new */
- X if (num >= 0) return (ERRSEP);
- X cp = getnum(cp, &num);
- X break;
- X case '-': /* range specified */
- X /* be sure range is new */
- X if (range >= 0) return (ERRRNG1);
- X /* be sure value was found */
- X if (num < 0) return (ERRRNG2);
- X range = num; /* save first value */
- X num = -1;
- X ++cp;
- X break;
- X case '\000': /* string/specification end */
- X case ',': /* specification end */
- X /* be sure value was found */
- X if (num < 0) return (ERRNUL);
- X /* range of one if not specified */
- X if (range < 0) range = num;
- X /* set range as increasing if needed */
- X if (range > num) {
- X i = num;
- X num = range;
- X range = i;
- X }
- X /* check against minimum */
- X if (num < minimum) return (ERRMIN);
- X /* check against maximum */
- X if (range > maximum) return (ERRMAX);
- X /* update truth vector */
- X for (i = range; i <= num; ++i)
- X vector[i] = !negate;
- X negate = FALSE;
- X /* specification done */
- X num = range = -1;
- X if (!*cp) return (FALSE);
- X ++cp;
- X break;
- X default:
- X return (ERRBAD);
- X }
- X}
- X
- X#ifdef DEBUG
- X
- X/* Display the specified string followed by a dump of the specified
- X truth vector.
- X*/
- X
- Xstatic void dump(string, vector, minimum, maximum)
- Xchar *string;
- XBOOL vector[];
- Xint minimum, maximum;
- X{
- X register int i;
- X
- X if (vector[0] == UNSET) return;
- X fputs(string, stderr);
- X for (i = minimum; i <= maximum; ++i)
- X if (vector[i])
- X fputc('T', stderr);
- X else
- X fputc('-', stderr);
- X fputc('\n', stderr);
- X}
- X
- X#endif DEBUG
- X
- X/* Evaluate a specific series of time specifications relative to the
- X current time. Return TRUE if current time is within them. Update
- X count to reflect the number of specs processed.
- X*/
- X
- Xstatic BOOL within(specs, count)
- Xchar **specs;
- Xint *count;
- X{
- X register int i, code;
- X
- X tty = UNSET;
- X for (i = 0; i < 60; ++i) min[i] = UNSET;
- X for (i = 0; i < 24; ++i) hour[i] = UNSET;
- X for (i = 0; i < 32; ++i) mday[i] = UNSET;
- X for (i = 0; i < 13; ++i) mon[i] = UNSET;
- X for (i = 0; i < 99; ++i) year[i] = UNSET;
- X for (i = 0; i < 8; ++i) wday[i] = UNSET;
- X *count = 0;
- X if (**specs == '-') ++*specs;
- X do {
- X#ifdef DEBUG
- X fputs("processing specification: ", stderr);
- X fputs(*specs, stderr);
- X fputc('\n', stderr);
- X#endif DEBUG
- X switch (**specs) {
- X case TTY:
- X if (code = ttychk(*specs))
- X error("tty", *specs, code);
- X break;
- X case MIN:
- X if (code = expand(*specs, min, 0, 59))
- X error("minute", *specs, code);
- X break;
- X case HOUR:
- X if (code = expand(*specs, hour, 0, 23))
- X error("hour", *specs, code);
- X break;
- X case MDAY:
- X if (code = expand(*specs, mday, 1, 31))
- X error("day of month", *specs, code);
- X break;
- X case MON:
- X if (code = expand(*specs, mon, 1, 12))
- X error("month", *specs, code);
- X break;
- X case YEAR:
- X if (code = expand(*specs, year, 87, 99))
- X error("year", *specs, code);
- X break;
- X case WDAY:
- X if (code = expand(*specs, wday, 0, 7))
- X error("day of week", *specs, code);
- X if (wday[0] || wday[7])
- X wday[0] = wday[7] = TRUE;
- X break;
- X default:
- X error("invalid specification: ", *specs, 0);
- X }
- X ++specs;
- X ++*count;
- X if (**specs == '-') ++*specs;
- X } while (**specs != OR && **specs != PATH);
- X if (**specs == OR) {
- X if (*(*specs+1) && (*(*specs+1) != 'r' || *(*specs+2)))
- X error("invalid specification: ", *specs, 0);
- X ++*count;
- X }
- X
- X#ifdef DEBUG
- X fputs("acceptible restrictions are...\n", stderr);
- X dump(" minutes: ", min, 0, 59);
- X dump(" hours: ", hour, 0, 23);
- X dump(" days of week: ", wday, 0, 6);
- X dump(" days of month: ", mday, 1, 31);
- X dump(" months: ", mon, 1, 12);
- X dump(" years: ", year, 87, 99);
- X if (tty != UNSET) {
- X fputs("(also no restriction on tty '", stderr);
- X fputs(ttynm, stderr);
- X if (tty) fputs("' - PASSED)\n", stderr);
- X else fputs("' - FAILED)\n", stderr);
- X }
- X fputc('\n', stderr);
- X#endif DEBUG
- X
- X return (tty && min[timenow->tm_min] && hour[timenow->tm_hour] &&
- X wday[timenow->tm_wday] && mday[timenow->tm_mday] &&
- X mon[timenow->tm_mon] && year[timenow->tm_year]);
- X}
- X
- Xvoid main(argc, argv, environ)
- Xint argc;
- Xchar **argv, *environ[];
- X{
- X register int i;
- X register BOOL runable = FALSE;
- X register char *cp;
- X BOOL testing = **argv != '-';
- X int count;
- X time_t clock;
- X FILE *acfp;
- X char buf[MAXENT];
- X char *fargv[MAXARGS];
- X char shell[MAXSH];
- X
- X (void) time(&clock);
- X timenow = localtime(&clock);
- X ++(timenow->tm_mon);
- X
- X#ifdef DEBUG
- X min[timenow->tm_min] = TRUE;
- X hour[timenow->tm_hour] = TRUE;
- X wday[timenow->tm_wday] = TRUE;
- X mday[timenow->tm_mday] = TRUE;
- X mon[timenow->tm_mon] = TRUE;
- X year[timenow->tm_year] = TRUE;
- X
- X fputs("time now is...\n", stderr);
- X dump(" minute: ", min, 0, 59);
- X dump(" hour: ", hour, 0, 23);
- X dump(" day of week: ", wday, 0, 6);
- X dump(" day of month: ", mday, 1, 31);
- X dump(" month: ", mon, 1, 12);
- X dump(" year: ", year, 87, 99);
- X fputc('\n', stderr);
- X#endif DEBUG
- X
- X if (argc < 2) {
- X if (!(acfp = fopen(ACFILE, "r")))
- X error("could not open control file: ", ACFILE, 0);
- X /* find this user's entry in the control file */
- X while (!user && fgets(buf, MAXENT, acfp))
- X if (i = userchk(buf)) {
- X for (cp = buf; *cp && !strchr(" \t#\n", *cp);
- X ++cp) ;
- X *cp = '\000';
- X error("user", buf, i);
- X }
- X if (!user) error(name, " not in control file", 0);
- X /* find the end of the first line */
- X for (cp = buf; *cp && !strchr("#\n", *cp); ++cp) ;
- X *cp = '\000';
- X /* append continuation lines */
- X while (count = MAXENT - (cp - buf)) {
- X i = fgetc(acfp);
- X if (!strchr(" \t#\n", i)) break;
- X (void) ungetc(i, acfp);
- X if (!fgets(cp, count, acfp)) break;
- X while (*cp && !strchr("#\n", *cp)) ++cp;
- X *cp = '\000';
- X }
- X (void) fclose(acfp);
- X#ifdef DEBUG
- X fputs("control entry: ", stderr);
- X fputs(buf, stderr);
- X fputc('\n', stderr);
- X#endif DEBUG
- X argc = 0;
- X argv = fargv;
- X argv[argc++] = cp = buf;
- X /* process arguments */
- X while (*cp) {
- X /* scan past last argument */
- X while (*cp && *cp != ' ' && *cp != '\t') ++cp;
- X /* terminate it with null */
- X if (*cp) *cp++ = '\000';
- X /* find the next argument */
- X while (*cp && (*cp == ' ' || *cp == '\t')) ++cp;
- X if (*cp) {
- X /* found one, enter it into argv */
- X if (argc == MAXARGS)
- X error("too many arguments ",
- X "in control file", 0);
- X argv[argc++] = cp;
- X }
- X }
- X argv[argc] = NULL;
- X#ifdef DEBUG
- X for (i = 1; i < argc; ++i) {
- X fputs("found specification: ", stderr);
- X fputs(argv[i], stderr);
- X fputs("\n", stderr);
- X }
- X fputs("\n", stderr);
- X#endif DEBUG
- X }
- X
- X for (i = 1; i < argc; ++i) if (*argv[i] == PATH) break;
- X if (i == argc)
- X error("full pathname to exec() required", "", 0);
- X
- X if (**(++argv) == PATH) runable = TRUE;
- X else do {
- X runable |= within(argv, &count);
- X argv += count;
- X } while (**argv != PATH);
- X
- X if (runable) {
- X#ifdef DEBUG
- X fputs("\ntime and tty IS within specifications\n", stderr);
- X#endif DEBUG
- X /* set the shell buffer to be "SHELL=pathname" */
- X (void) strcpy(shell, "SHELL=");
- X (void) strcat(shell, *argv);
- X /* fix argv[0] to point to '-progname' */
- X if (cp = strrchr(*argv, '/')) {
- X *cp = '-';
- X (void) strcpy(*argv, cp);
- X }
- X /* set cp to point to the pathname to execute */
- X cp = shell + 6;
- X /* find and fix the SHELL environment variable */
- X for (i = 0; environ[i]; ++i) {
- X if (!strncmp(environ[i], "SHELL=", 6)) {
- X environ[i] = shell;
- X break;
- X }
- X }
- X if (testing) {
- X fputs(cp, stderr);
- X fputs(": ", stderr);
- X for (i = 0; argv[i]; ++i) {
- X fputs(" \"", stderr);
- X fputs(argv[i], stderr);
- X fputc('"', stderr);
- X }
- X fputc('\n', stderr);
- X exit(0);
- X }
- X (void) execve(cp, argv, environ);
- X error("could not exec() ", cp, 0);
- X } else {
- X#ifdef DEBUG
- X fputs("\ntime or tty is NOT within specifications\n", stderr);
- X#endif DEBUG
- X fputs("\n*** your access ", stderr);
- X if (ttynm) fputs("(on this tty port) ", stderr);
- X fputs("is not permitted at this time ***\n", stderr);
- X }
- X}
- SHAR_EOF
- fi
- if test -f 'access.man'
- then
- echo shar: "will not over-write existing file 'access.man'"
- else
- sed 's/^X//' << \SHAR_EOF > 'access.man'
- X.TH ACCESS l "19 June 1988"
- X.SH NAME
- Xaccess \- limit system usage to specified ttys and times
- X.SH SYNTAX
- X.B "/usr/local/etc/access"
- X.SH DESCRIPTION
- X.I Access
- Xprovides a simple yet powerful method of limiting user access to a
- Xsystem. Simply specify
- X.B /usr/local/etc/access
- Xin place of a login shell in the password file for each user who is to
- Xhave restricted accessibility to a system.
- X.I Access
- Xwill lookup that user's entry in the control file
- X.B /usr/local/lib/access
- Xand execute the specified real login shell (with optional arguments) if
- Xthe current tty and time falls within one or more of the access
- Xconstraints given.
- X.PP
- XEach entry in the control file has the form:
- X.PP
- Xuserspec [constraint1] [...[-]o[r] constraintN]
- X.br
- X full_pathname [args]
- X.PP
- XBlank lines are ignored, while `#' marks the start of a comment which
- Xcontinues to the end of the line. Entries may be continued by indenting
- Xcontinuation lines with whitespace (blanks or tabs). Entries are
- Xlimited to a maximum of 1k characters.
- X.PP
- XAccessibility constraints limit the tty port and/or up to 6
- Xaccessibility classes of time. Accessibility constraints are composed
- Xof multiple specifications separated by spaces and/or tabs. Additional
- Xconstraints may be specified by connecting them with the
- X.B OR
- Xoperator (see below).
- X.PP
- XEach specification within an accessibility constraint is composed of a
- Xletter (optionally preceded by `-') followed by the specification. They
- Xare as follows:
- X.PP
- X.nf
- X.ta 0.8i 1.6i 2.4i
- X class range description
- X ----- ----- -----------
- X `t' tty name restrictor
- X `m' 0-59 minute restrictor
- X `h' 0-23 hour restrictor
- X `w' 0-6 day of week restrictor (0 = Sunday)
- X `D' 1-31 day of month restrictor
- X `M' 1-12 month restrictor
- X `Y' 87-99 year restrictor
- X `o[r]' logical OR separator
- X.fi
- X.PP
- XWhere an accessibility class is not specified within an accessibility
- Xconstraint, no restriction will be applied to that class. For instance,
- Xif `m' does not appear within an accessibility constraint then
- Xaccessibility will not be constrained by the current minute.
- X.PP
- XNumeric accessibility classes are specified with single values or a
- Xrange of values separated by `-'. Multiple specifications may be given
- Xat one time separated by `,'. Any given class may appear more than
- Xonce. The sense of any specific specification may be negated by `!'
- X(or `^'). Further, `*' (or `@') may be used to indicate infinity. For
- Xexample, each of the following are equivalent: "h0-23", "h*-23",
- X"h0-*", "h*-*", "h*", "h0,1,2-10 h11-*".
- X.PP
- XThe tty accessibility class is composed of one or more string segments,
- Xone of which must match the tail of the current tty's name. As with the
- Xnumeric accessibility classes, "-,!^*@" are all supported.
- X.PP
- XThe first entry in the control file, in which the current user's name is
- Xmatched within the "userspec", will be the entry processed for that
- Xuser. The "userspec" is composed of one or more full usernames, one of
- Xwhich must exactly match the current user's name. As with the numeric
- Xand tty accessibility classes, ",!^*@" are all supported. Note that
- Xranges specified by `-' are NOT supported in the "userspec".
- X.SH EXAMPLES
- Xjoe h9-17 /bin/csh
- X.IP "" 5
- XAllow `joe' access only between 9AM and 5PM.
- X.PP
- Xuucp,net ttya7 w1-5 h*,!9-17 or ttya0-ab w0,6
- X.br
- X /usr/lib/uucp/uucico
- X.IP "" 5
- XAllow `uucp' and `net' access on (/dev/t)tya7 weekdays except between
- X9AM and 5PM
- X.B or
- Xon (/dev/t)tya0 thru (/dev/tty)ab (anytime) on weekends. Note the "*"
- Xis required in the hour specification. Otherwise, since "h" appeared -
- Xhours would be constrained, no unrestricted hours specified, then
- Xfurther constrained to not be between 9 and 17. In other words no hour
- Xwould be acceptable and only the second accessibility constraint could
- Xpossibly pass.
- X.PP
- X*,!root Y*-87 t*,!console or M*-9 Y88 t*,!console /bin/sh
- X.IP "" 5
- XAllow everyone access except `root' thru September 1988 on any tty
- Xexcept consoles. Note that if
- X.I access
- Xis specified as `root's login shell as this example implies, then `root'
- Xmust have an entry somewhere following this example entry. Alternately,
- X`root' may have an entry before this one in which event the ",!root"
- Xwould be extraneous since
- X.I access
- Xwould never get this far for user `root'.
- X.PP
- Xuucp /usr/lib/uucp/uucico
- X.br
- X* /bin/csh
- X.IP "" 5
- XGive `uucp' unrestricted access to `uucico' and everyone else
- Xunrestricted access to the `csh'. Effectively,
- X.I access
- Xwould not be doing anything. This would be one method of removing
- Xaccess constraints for everyone without changing the password file.
- X.SH TESTING
- XIf
- X.I access
- Xis invoked from a shell then the access constraints will be derived from
- Xits arguments (do not specify the `userspec'). In place of actually
- Xexecuting the real login shell specified, that program's name and its
- Xargument vector will be displayed.
- X.SH INSTALLATION
- XBe sure to disable users ability to change their login shell and thereby
- Xdefeat this control. For example, "chmod o-x /usr/ucb/chsh".
- X.SH "SEE ALSO"
- XFiles: /etc/passwd and /usr/local/lib/access
- X.SH DIAGNOSTICS
- XIf at least one accessibility constraint passes, the presence of
- X.I access
- Xis invisible. If no accessibility constraint passes, then a message is
- Xissued and the user immediately logged off.
- X.SH AUTHOR
- XGeorge M. Sipe currently (7/88) at rebel!george
- SHAR_EOF
- fi
- exit 0
- # End of shell archive
- --
- George M. Sipe, Phone: (404) 662-1533
- Tolerant Systems, 6961 Peachtree Industrial, Norcross, GA 30071
- UUCP: ...!{decvax,hplabs,linus,rutgers,seismo}!gatech!rebel!george
-